﻿using System.Collections.Concurrent;
using Omu.ValueInjecter;
using Wolfpack.Periscope.Core.Infrastructure;
using Wolfpack.Periscope.Core.Interfaces;
using Wolfpack.Periscope.Core.Interfaces.Events;
using Wolfpack.Periscope.Core.Interfaces.Messages;

namespace Wolfpack.Periscope.Core.Plugins
{
    public class PanelRefreshPlugin : IDashboardPlugin
    {
        private readonly ConcurrentDictionary<string, WidgetUpdateRequest> _updateCache;
        private readonly IDashboardInfrastructure _infrastructure;

        private TinyMessageSubscriptionToken _updateToken;
        private TinyMessageSubscriptionToken _refreshPanelToken;

        public PanelRefreshPlugin(IDashboardInfrastructure infrastructure)
        {
            _infrastructure = infrastructure;
            _updateCache = new ConcurrentDictionary<string, WidgetUpdateRequest>();
        }

        public void Initialise()
        {
            _updateToken = _infrastructure.MessageBus.Subscribe<WidgetUpdateCommand>(HandleWidgetUpdateRequest,
                OnlyCacheableUpdateRequestsFilter);
            _refreshPanelToken = _infrastructure.MessageBus.Subscribe<PanelLoadedEvent>(HandlePanelLoaded);
        }

        private static bool OnlyCacheableUpdateRequestsFilter(WidgetUpdateCommand msg)
        {
            return msg.Content.NoCache == false;
        }

        public void Start()
        {
        }

        private void HandleWidgetUpdateRequest(WidgetUpdateCommand msg)
        {
            _updateCache[msg.Content.TargetWidgetId] = msg.Content;
        }
        
        private void HandlePanelLoaded(PanelLoadedEvent msg)
        {
            foreach (var kvpCacheUpdate in _updateCache)
            {
                var update = new WidgetUpdateRequest();
                update.InjectFrom<LoopValueInjection>(kvpCacheUpdate.Value);

                // ensure we don't try to re-cache this and that we target the
                // panel that is loading
                update.NoCache = true;
                update.TargetPanelInstanceId = msg.Content.PanelInstanceId;

                _infrastructure.MessageBus.PublishAsync(new WidgetUpdateCommand(this, update));
            }
        }

        public void Dispose()
        {
            if (_updateToken != null)
                _updateToken.Dispose();
            if (_refreshPanelToken != null)
                _refreshPanelToken.Dispose();
        }
    }
}